package com.mapbased.sfw.model;

import java.io.StringReader;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.mapbased.sfw.ses.SessionStore;
import com.mapbased.sfw.site.SiteConfig;
import com.mapbased.sfw.store.PathData;
import com.mapbased.sfw.store.PathDataType;
import com.mapbased.sfw.store.SiteStore;
import com.mapbased.sfw.util.logging.ESLogger;
import com.mapbased.sfw.util.logging.Loggers;

public class Site {
	static ESLogger log = Loggers.getLogger(Site.class);
	
	public static final String[] INDEXS=new String[]{
		"index","index.html","index.htm","default.html","default.htm"
		
	};
	 
	private Site backSite=null;;

 	SiteStore siteStore;
	SessionStore sessionStore = new SessionStore();
	public final NavItem root = new NavItem("/");
	

	private ConcurrentMap<String, PathBag> fragments = new ConcurrentHashMap<String, PathBag>();
	
	private final ConcurrentMap<String, GeneralEnum> enums
		=new ConcurrentHashMap<String, GeneralEnum>();
	public final SiteConfig conf=new SiteConfig();
	
	
	public Site(SiteStore ss) {
		this.siteStore = ss;

		List<PathData> kvs = ss.getAllPathData();

		

		for (PathData kv : kvs) {
			switch(kv.type){
				case Page:
					this.initPage(kv);
					break;
				case Res:
					
					ResBag res=new ResBag(kv);
					res.site=this;
					this.fragments.put(kv.path, res);
					break;
				case Config:
					this.conf.update(kv);
					break;
				case Enum:
					
					this.enums.put(kv.path, new GeneralEnum(kv));
					break;
			}
			
		}

	}
	public GeneralEnum getEnum(String name){
		GeneralEnum ge=	this.enums.get(name);
		if(ge==null&&this.backSite!=null){
			return this.backSite.getEnum(name);
		}
		return ge;
	}
	public String getConfig(String name){
		String s=this.conf.vars.get(name);
		if(s==null&&backSite!=null){
			s=this.backSite.getConfig(name);
		}
		return s;
	}
	private void initPage(PathData kv){
		FragmentBag bag = new FragmentBag();
		Fragment f = null;
		try {
			f = this.loadPage(kv);
		} catch (DocumentException e) {
			log.error("Error while load page:{}", e, kv.path);
			return;
		}
		bag.fragment = f;

		PathBag back = this.fragments.putIfAbsent(kv.path, bag);

		if (back instanceof FragmentBag) {
			((FragmentBag)back).fragment = f;
		} 
		this.addPathToNavItem(f);
	}
	/**
	 * 获取给定路径的导航项
	 * @param path
	 * @return
	 */
//	public NavItem getNavItem(String path){
//
//
//		int i=path.indexOf("/");
//		NavItem nav=root;
//		while(i>0){
//			int j=path.indexOf("/", i);
//			if(j<0){
//				break;
//			}
//			
//			String s=path.substring(i,j);
//			nav=nav.getChild(s);
//			i=j;
//			
//		}
//		return nav;
//	}
	public void addPathToNavItem(Fragment f) {

		String p = f.path;
		NavItem nav = root;
		if (p.startsWith("/")) {
			p = p.substring(1);
		}
		while (true) {
			int edx = p.indexOf("/");
			if (edx > 0) {
				NavItem nn = new NavItem(p.substring(0, edx));
				nav = nav.add(nn);

				p = p.substring(edx + 1);
			} else {
				if (p.endsWith(".dir")) {
					p = p.substring(0, p.length() - 4);
				}
				NavItem nn = new NavItem(p);
				if (f instanceof Page) {
					Page page = (Page) f;
					nn.setCaption(page.getCaption());
					nn.setOrder(page.getOrder());
				}
				nav.add(nn);
				break;
			}
		}
	}

	public PathBag  getPathBag(RenderContext rc) {
		String path = rc.getPagePath();
		 

		 

		return getPathBag(path);
	}
	private PathBag getFragmentsCheckBackSite(String path){
		PathBag bag = fragments.get(path);
		if(bag==null&&this.backSite!=null){
			bag=this.backSite.getFragmentsCheckBackSite(path);
		}
		return bag;
	}
	public PathBag  getPathBag(String path) {
		PathBag bag = getFragmentsCheckBackSite(path);
		if(bag!=null){
			return bag;
		}
		if (path.endsWith("/")) {
			for(int i=0;bag==null&&i<INDEXS.length;i++){
				bag=getFragmentsCheckBackSite(path+INDEXS[i]);
			}
		}
		 

		return bag;
	}
		
 

	public static String getMasterPath(String path) {

		int idx = path.lastIndexOf("/", path.length());
		if (!path.endsWith(".m")) {

			return path.substring(0, idx) + "/index.m";

		} else {
			if (idx == 0) {
				return null;
			} else {
				return path.substring(0, path.lastIndexOf("/", idx - 1))
						+ "/index.m";
			}
		}
	}
	/**
	 * @deprecated because force type changes
	 * @param path
	 * @return
	 */
	public FragmentBag getFragmentBag(String path) {
		return (FragmentBag)this.getFragmentsCheckBackSite(path);
	}

	public FragmentBag getMasterFragmentBag(String masterp) {

		if (masterp == null) {
			return null;
		}
		FragmentBag fb =(FragmentBag) this.getFragmentsCheckBackSite(masterp);
		if (fb != null) {
			return fb;
		}
		if (masterp.equalsIgnoreCase("/index.m")) {
			fb = new FragmentBag();
			fb.fragment = null;
		} else {
			MasterBag mb = new MasterBag();
			mb.parent = this.getFragmentBag(masterp);
			fb = mb;
		}
		FragmentBag rfb =(FragmentBag) this.fragments.putIfAbsent(masterp, fb);
		if (rfb != null) {
			return rfb;
		}
		return fb;

	}

	public void dynamicAddPage(String path, String content) {

	}

	public void updateNav() {

	}

	private Fragment createEmptyFromPath(String path) {
		Fragment f = null;
		if (path.endsWith(".f")) {
			f = new Fragment();
		}
		f = new Page();
		f.path = path;
		return f;
	}

	private Fragment loadPage(PathData kv) throws DocumentException {
		SAXReader reader = new SAXReader();
		reader
				.setEntityResolver(com.mapbased.sfw.util.WfwEntityResolver.INSTANCE);

		Document doc = reader.read(new StringReader(kv.getStrValue()));

		Element root = doc.getRootElement();

		LoadContext lc = new LoadContext(this);
		

		Fragment f = this.createEmptyFromPath(kv.path);
		lc.loadingFragment=f;
		f.parseXml(root, lc);
		

		return f;

	}
	public Site getBackSite() {
		return backSite;
	}

}
